package puzzle.view;


import puzzle.helper.PhotoRescaled;
import puzzle.model.*;

import java.util.List;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;

import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Window;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.text.StyledDocument;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleContext;
import javax.swing.text.StyleConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.rtf.RTFEditorKit;

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.File;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;


// This class opens a start page with 10 photos to choose from.
// It also gives informations on how to play and displays records.
public class StartPageGui {

    public static void main(String[] args) {

        String difficultiesFilePath = "resources/difficulties.txt";
        String photosDirectoryPath = "resources/jpg/";
        String moveRecordsDirectoryPath = "resources/moveRecords/";
        String timeRecordsDirectoryPath = "resources/timeRecords/";        
        
        new StartPageGui(difficultiesFilePath, photosDirectoryPath, 
                moveRecordsDirectoryPath, timeRecordsDirectoryPath);
        
    }    

    private String photosDirectoryPath;
    private PuzzleModel pm;
    
    private static JFrame f;
    private static JPanel centralPanel;
    private JPanel buttonsPanel;
    
    private JPanel gamePanel;
    private JPanel settingsPanel;
    private JTextPane tp;        
    private JPanel photoPanel;
    private JPanel elementsPanel;
    private ButtonGroup group;
    
    private static JPanel recordsPanel;
    private static JPanel recordsImagePanel;
    private static JTextPane recordsMovesTp;
    private static JTextPane recordsTimeTp;
    
    private RTFEditorKit kit;
    private static StyledDocument dsd;    
    
    
    StartPageGui(String difficultiesFilePath, String photosDirectoryPath, String moveRecordsDirectoryPath, String timeRecordsDirectoryPath){
        
        this.photosDirectoryPath = photosDirectoryPath;
        pm = new PuzzleModel(difficultiesFilePath, moveRecordsDirectoryPath, timeRecordsDirectoryPath);
        launchFrame();
        
    }
    
    private void launchFrame() {                 
        
        loadCentralPanel();     
        loadButtonsPanel();
        loadGamePanel();
        loadSettingsPanel();
        loadRecordsPanel();        
        
        f = new JFrame("Puzzle - home");
        f.setLayout(new BorderLayout());
        f.add(centralPanel, BorderLayout.CENTER);
        f.add(buttonsPanel, BorderLayout.SOUTH);
        f.pack();
        f.setResizable(false);
        f.setLocation(0, 0);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
        f.setVisible(true);
        
    }    
    
    // Prepares a main panel for the window.
    private void loadCentralPanel() {        
        
        tp = new JTextPane();                      
        tp.setEditable(false);
        tp.setBackground(new Color(245,245,210));
        tp.setBorder(BorderFactory.createMatteBorder( 5, 10, 0, 10, new Color(245,245,210)) );
        
        kit = new RTFEditorKit();        
        tp.setEditorKit(kit);
        
        StyleContext sc = new StyleContext();
        dsd = new DefaultStyledDocument(sc);
        
        Style iconStyle = sc.getStyle(StyleContext.DEFAULT_STYLE);
        StyleConstants.setAlignment(iconStyle, StyleConstants.ALIGN_CENTER);
    
        // When the main window is open for the first time it shows a photo stored in resources directory. 
        Icon icon = new ImageIcon("resources/StartPage.jpg");
        StyleConstants.setIcon(iconStyle, icon);
        try {
            dsd.insertString(0, "Ignored", iconStyle);               
        } catch (BadLocationException ble) {
            System.err.println(ble.getMessage());
        }            
        tp.setDocument(dsd);        
        
        centralPanel = new JPanel();
        centralPanel.setPreferredSize(new Dimension(750, 360));
        centralPanel.setBackground(new Color(225,225,200)); 
        centralPanel.setLayout(new BorderLayout());
        
        centralPanel.add(tp);
    }
    
    // Prepares a panel containing buttons to be displayed below the central panel.
    private void loadButtonsPanel() {
        
        buttonsPanel =new JPanel();
        buttonsPanel.setBackground(new Color(245,245,210));
        buttonsPanel.setBorder(BorderFactory.createMatteBorder( 0, 4, 5, 4, new Color(245,245,210)) );
        buttonsPanel.setLayout(new FlowLayout());
        
        JButton[] mainButtons = new JButton[] {
            new JButton("How to play"),
            new JButton("Puzzle"),
            new JButton("Settings"),
        };
        
        mainButtons[0].addActionListener(new HowToPlayHandler());
        mainButtons[1].addActionListener(new PuzzleHandler());
        mainButtons[2].addActionListener(new SettingsHandler());
        
        for (JButton mainButton : mainButtons) {
            mainButton.setBackground(new Color(190,190,165));
            mainButton.setForeground(Color.RED);
            mainButton.setPreferredSize(new Dimension(250, 40));
            mainButton.setFont(new Font("TimesNewRoman", Font.BOLD, 16));
            buttonsPanel.add(mainButton);
        } 
        
     }       
    

     // Prepares a panel that paints images.
     private void loadGamePanel() {              
        
        List<Photo> photos = pm.getAllPhotos();
        String imageName = photos.get(0).getName();
        String imagePath = photosDirectoryPath + imageName + ".jpg";
        PhotoRescaled photo = new PhotoRescaled(imagePath, 250, 200);
        photo.setName(imageName);
        photo.addMouseListener(new PlayHandler());
        
        photoPanel = new JPanel();
        photoPanel.setBackground(new Color(245,245,210));        
        photoPanel.setPreferredSize(new Dimension(360, 220));
        photoPanel.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.CENTER;        
        photoPanel.add(photo, c);
        
        JButton[] photoButtons = new JButton[] {
        new JButton("<  Previous"),
        new JButton("Next  >"),        
        };
                
        for (JButton photoButton : photoButtons) {
            photoButton.setBackground(new Color(200,200,175));
            photoButton.setForeground(new Color(0, 0, 150));
            photoButton.setPreferredSize(new Dimension(100, 30));
            photoButton.setFont(new Font("TimesNewRoman", Font.BOLD, 12)); 
            photoButton.addActionListener(new PhotoButtonsHandler());
        }  
        
        JPanel mainPanel = new JPanel();
        mainPanel.setBackground(new Color(245,245,210));
        mainPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 50));
        
        mainPanel.add(photoButtons[0]);
        mainPanel.add(photoPanel);
        mainPanel.add(photoButtons[1]);        
        
        elementsPanel = new JPanel();
        elementsPanel.setBackground(new Color(245,245,210));
        elementsPanel.setPreferredSize(new Dimension(0, 90));
        elementsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 20));
                
        group = new ButtonGroup();        
        List<String> labels = photos.get(0).getDifficulties();
        for (String label : labels) {
            JRadioButton button = new JRadioButton(label);
            button.setBackground(new Color(245,245,210));
            elementsPanel.add(button);
            group.add(button);
        }
        JRadioButton selected = (JRadioButton)elementsPanel.getComponent(0);
        selected.setSelected(true);
        
        gamePanel = new JPanel();
        gamePanel.setBackground(new Color(245,245,210));
        gamePanel.setLayout(new BorderLayout()); 
        
        gamePanel.add(mainPanel, BorderLayout.CENTER);
        gamePanel.add(elementsPanel, BorderLayout.SOUTH);
         
    }
     
     
    // Prepares a panel containing settings buttons. 
    private void loadSettingsPanel() {
        
        settingsPanel = new JPanel();
        settingsPanel.setBackground(new Color(245,245,210));
        settingsPanel.setPreferredSize(new Dimension(260, 360));        
        settingsPanel.setBorder(BorderFactory.createMatteBorder( 30, 10, 0, 0, new Color(245,245,210)) );
        settingsPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
        
        JButton[] settingsButtons = new JButton[] {
            new JButton("Replace photo"),
            new JButton("Replace level"),
            new JButton("Add new level"),
            new JButton("Remove selected level"),
            new JButton("Show records"),
            new JButton("Clear selected records"),
            new JButton("Clear all records"),
        };
        
        settingsButtons[0].addActionListener(new ReplacePhotoHandler());
        settingsButtons[1].addActionListener(new ReplaceLevelHandler());
        settingsButtons[2].addActionListener(new AddLevelHandler());
        settingsButtons[3].addActionListener(new RemoveLevelHandler());
        settingsButtons[4].addActionListener(new RecordsHandler());
        settingsButtons[5].addActionListener(new RecordsHandler());
        settingsButtons[6].addActionListener(new ClearAllRecordsHandler());
                
        for (JButton button : settingsButtons) {
            button.setBackground(new Color(200,200,175));
            button.setForeground(new Color(0, 0, 150));         
            button.setFont(new Font("TimesNewRoman", Font.BOLD, 12));
            if( !button.equals(settingsButtons[1]) && !button.equals(settingsButtons[2]) ) {
                button.setPreferredSize(new Dimension(190, 38));            
                settingsPanel.add(button);
            }
        }     
        
        List<String> levels = new ArrayList<String>();
        for (int i=3; i<=9; i++) {
            for (int j=3; j<=9; j++) {
                levels.add(i + "x" + j);
            }
        }        
        
        for(int i=1; i<=2; i++) {
            
            JComboBox levelsComboBox = new JComboBox(levels.toArray());             
            levelsComboBox.setBackground(new Color(200,200,175));
            levelsComboBox.setForeground(new Color(0, 0, 150));
            levelsComboBox.setPreferredSize(new Dimension(50, 38));
            levelsComboBox.setFont(new Font("TimesNewRoman", Font.BOLD, 12));           
        
            JPanel levelsPanel = new JPanel();
            levelsPanel.setPreferredSize(new Dimension(190, 38));
            levelsPanel.setLayout(new BorderLayout());
            levelsPanel.add(settingsButtons[i], BorderLayout.CENTER);
            levelsPanel.add(levelsComboBox, BorderLayout.EAST);
            settingsPanel.add(levelsPanel, i);
            
        }         
        
    } 
     
     
    // Prepares a panel that displays records.
    private void loadRecordsPanel() {
        
        recordsPanel =new JPanel();
        recordsPanel.setBackground(new Color(245,245,210));
        recordsPanel.setLayout(new FlowLayout());
         
        recordsMovesTp = new JTextPane();
        recordsMovesTp.setEditable(false);
        recordsMovesTp.setBackground(new Color(245,245,210));
        
        recordsImagePanel =new JPanel();
        recordsImagePanel.setBackground(new Color(245,245,210));
        recordsImagePanel.setLayout(new FlowLayout(FlowLayout.CENTER, 40, 70));
                
        recordsTimeTp = new JTextPane();
        recordsTimeTp.setEditable(false);
        recordsTimeTp.setBackground(new Color(245,245,210));
        
        recordsPanel.add(recordsMovesTp);
        recordsPanel.add(recordsImagePanel);
        recordsPanel.add(recordsTimeTp);
    }
    
    
    // This class displays informations on how to play. 
    class HowToPlayHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
            
            centralPanel.removeAll();
            centralPanel.repaint();            
            centralPanel.add(tp);
            
            InputStream in = null;
            try {
                File file = new File("resources/howToPlay.rtf");
                in = new FileInputStream(file);
                dsd.remove(0, dsd.getLength());
                kit.read(in,dsd,0);                   
                tp.setDocument(dsd);                
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            } finally {
                try {
                    in.close();
                } catch (IOException ioe) {
                    System.out.println(ioe.getMessage());
                }
            }
                
        }
    }
    
    
    // shows a panel with photos to choose from.
    class PuzzleHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
            
            elementsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 40, 20));
            photoPanel.setPreferredSize(new Dimension(360, 220));
            
            PhotoRescaled thisImage = (PhotoRescaled)photoPanel.getComponent(0);
            String imageName = thisImage.getName();
            String imagePath = photosDirectoryPath + imageName + ".jpg";
            PhotoRescaled newImage = new PhotoRescaled(imagePath, 250, 200);
            newImage.setName(imageName);            
            newImage.addMouseListener(new PlayHandler());
            
            photoPanel.removeAll();
            photoPanel.repaint();
            photoPanel.add(newImage);
            photoPanel.validate();
            
            centralPanel.removeAll();
            centralPanel.repaint();
            centralPanel.add(gamePanel);           
            centralPanel.validate();
            
        }
    }
       
    
    // Shows a panel with settings options.
    class SettingsHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
            
            elementsPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 25, 0));
            photoPanel.setPreferredSize(new Dimension(250, 220));
            
            PhotoRescaled thisImage = (PhotoRescaled)photoPanel.getComponent(0);
            String imageName = thisImage.getName();
            String imagePath = photosDirectoryPath + imageName + ".jpg";
            PhotoRescaled newImage = new PhotoRescaled(imagePath, 210, 170);
            newImage.setName(imageName);
            
            photoPanel.removeAll();
            photoPanel.repaint();
            photoPanel.add(newImage);
            photoPanel.validate();
            
            centralPanel.removeAll();
            centralPanel.repaint();
            centralPanel.add(settingsPanel, BorderLayout.WEST);
            centralPanel.add(gamePanel, BorderLayout.CENTER);
            centralPanel.validate();
            
        }
    }
    
    
    // When a photo is clicked a main window of the game opens.
    class PlayHandler extends MouseAdapter{

       @Override
       public void mouseClicked(MouseEvent e) {
           
           String noOfElements = null;
           Enumeration elements = group.getElements();
           while (elements.hasMoreElements()) {
               AbstractButton button = (AbstractButton)elements.nextElement();
               if (button.isSelected()) {
                   noOfElements = button.getText();
                   break;
               }
           }
           
           if(noOfElements != null) {               
              
               // Close a main window of the game if it is already open.
               System.gc();  
               for (Window window : Window.getWindows()) {  
                   if ( !window.equals(f) ) {
                       window.dispose();
                   }  
               }

               // Prompt an user to give a name that can be stored in records files.
               String playerName = JOptionPane.showInputDialog(f, "Enter your name");
               if (playerName != null && playerName.length()==0) {
                   playerName = "Unknown";
               }

               if (playerName != null) {
                   
                   PhotoRescaled image = (PhotoRescaled)e.getSource();
                   
                   String imageName = image.getName();
                   String imagePath = photosDirectoryPath + imageName + ".jpg";                             
               
                   int xCoordinate = Integer.parseInt(noOfElements.split("x")[0]);
                   int yCoordinate = Integer.parseInt(noOfElements.split("x")[1]);
               
                   String recordFileName = imageName + "_" + noOfElements + ".txt";
                            
                   new PlayPuzzleGui(pm, recordFileName, imagePath, xCoordinate, yCoordinate, playerName);                   
                    
               }
               
           }           

        }
    }
    
    
    // When "Next >" or "< Previous" buttons are clicked a displayed photo is changed.
    class PhotoButtonsHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
            
            JButton clickedButton = (JButton)e.getSource();
            String clickedButtonText = clickedButton.getText();
            
            PhotoRescaled thisImage = (PhotoRescaled)photoPanel.getComponent(0);
            String thisImageName = thisImage.getName();
            
            List<Photo> photos = pm.getAllPhotos();
            String firstImageName = photos.get(0).getName();
            String lastImageName = photos.get(photos.size()-1).getName();
            
            if(  !( thisImageName.equals(firstImageName) && clickedButtonText.equals("<  Previous") ) && 
                 !( thisImageName.equals(lastImageName) && clickedButtonText.equals("Next  >") )  ) {            
                int buttonIndex;
                if (clickedButtonText.equals("Next  >") ) {
                    buttonIndex = 1;
                } else {
                    buttonIndex = -1;
                }
                
                int thisImageIndex = 0;
                for(Photo photo : photos) {
                    if ( photo.getName().equals(thisImageName) ){
                        thisImageIndex = photos.indexOf(photo);
                        break;
                    }
                }
                
                int nextImageIndex = thisImageIndex + buttonIndex;
                Photo nextPhoto = photos.get(nextImageIndex);
                String nextPath = photosDirectoryPath + nextPhoto.getName() + ".jpg";
                
                PhotoRescaled nextImage;
                if (thisImage.getMouseListeners().length!=0) {
                    nextImage = new PhotoRescaled(nextPath, 250, 200);
                    nextImage.addMouseListener(new PlayHandler());
                } else {
                    nextImage = new PhotoRescaled(nextPath, 210, 170);
                }  
                thisImage = null;
                nextImage.setName(nextPhoto.getName());                
                     
                photoPanel.removeAll();
                photoPanel.repaint();
                photoPanel.add(nextImage);
                photoPanel.validate();
                
                List<String> labels = nextPhoto.getDifficulties();
                displayLevels(labels);
                
            }
            
        }
    }   
    
    
    // This method replaces a selected photo.
    class ReplacePhotoHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {            
            
            JFileChooser fc = new JFileChooser();
            fc.showOpenDialog(f);
            File newFile = fc.getSelectedFile();                   
                                        
            try {  
                BufferedImage newImage = ImageIO.read(newFile);               
                
                // Newly added images are resized so that they have width between 250 to 800 and height between 250 to 570.
                double ratio = 1;
                if(newImage.getWidth()<250 || newImage.getHeight()<250) {
                    
                    double widthRatio = 1;
                    double heightRatio = 1;
                    if( newImage.getWidth()<250 ) {
                        widthRatio = (double)250/newImage.getWidth();
                    }
                    if (newImage.getHeight()<250) {
                        heightRatio = (double)250/newImage.getHeight();
                    }
                    ratio = Math.max(widthRatio, heightRatio);
                    
                } else if (newImage.getWidth()>800 || newImage.getHeight()>570) {
                                    
                    double widthRatio = 1;
                    double heightRatio = 1;
                    if( newImage.getWidth()>800 ) {
                        widthRatio = (double)800/newImage.getWidth();
                    }
                    if (newImage.getHeight()>570) {
                        heightRatio = (double)570/newImage.getHeight();
                    }
                    ratio = Math.min(widthRatio, heightRatio);
                    
                }
                    
                int img_width = (int)( newImage.getWidth()*ratio );
                int img_height = (int)( newImage.getHeight()*ratio );
                    
                if(img_width<250 || img_width>800 || img_height<250 || img_height>570) {
                    JOptionPane.showMessageDialog(f, "Selected photo cannot be rescaled. " +
                            "After it's rescaled it must be 250 to 800 wide and 250 to 570 high."); 
                } else {                     
                
                    int type = newImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : newImage.getType();
                    BufferedImage resizedImage = new BufferedImage(img_width, img_height, type);
                    Graphics2D g = resizedImage.createGraphics();
                    g.drawImage(newImage, 0, 0, img_width, img_height, null);
                    g.dispose();
                    
                    String imageName = photoPanel.getComponent(0).getName();            
                    String imagePath = photosDirectoryPath + imageName + ".jpg";            
                    ImageIO.write(resizedImage, "jpg", new File(imagePath)); 
                                
                    PhotoRescaled newRescaled = new PhotoRescaled(imagePath, 210, 170);
                    newRescaled.setName(imageName);                       
                        
                    photoPanel.removeAll();
                    photoPanel.repaint();
                    photoPanel.add(newRescaled);
                    photoPanel.validate();   
                
                    //Clear all records associated with the photo                  
                    Enumeration elements = group.getElements();
                    while (elements.hasMoreElements()) {
                            
                        AbstractButton button = (AbstractButton)elements.nextElement();                
                        String noOfElements = button.getText();
                
                        String recordsFileName = imageName + "_" + noOfElements + ".txt";
                        pm.clearRecords(recordsFileName);
                            
                    }
                    
                }                         
                
            } catch (Exception ex){
                System.out.println(ex.getMessage());
            }           
            
        }
    }   
    
    
    // This method replaces a selected difficulty for a displayed photo.
    class ReplaceLevelHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {               
            
            String imageName = photoPanel.getComponent(0).getName();
                
            String message = "Do you want to replace selected level for a displayed image?";
            int clearRecords = JOptionPane.showConfirmDialog(f, message, "Replace level", JOptionPane.OK_CANCEL_OPTION);
            if (clearRecords == JOptionPane.OK_OPTION) {
                
                JButton button = (JButton)e.getSource();
                JComboBox box = (JComboBox)button.getParent().getComponent(1);
                String levelToAdd = (String)box.getSelectedItem();
                
                String levelToDelete = null;
                Enumeration elements = group.getElements();
                while (elements.hasMoreElements()) {
                    AbstractButton nextButton = (AbstractButton)elements.nextElement();
                    if (nextButton.isSelected()) {
                        levelToDelete = nextButton.getText();
                        break;
                    }
                }
                    
                List<String> labels = pm.changeDifficulty(imageName, levelToAdd, levelToDelete);
                if ( labels.isEmpty() ) {                      
                    JOptionPane.showMessageDialog(f, "Selected level has been already added.");                     
                } else {             
                    displayLevels(labels);                        
                } 
                
            }
                
        }           
    }
    
    
    // This method adds a new difficulty for a selected photo.
    class AddLevelHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {             
            
            if( elementsPanel.getComponentCount()>=6 ) {  
                
                JOptionPane.showMessageDialog(f, "You cannot add more then six levels."); 
                
            } else {
                
                String imageName = photoPanel.getComponent(0).getName();
                
                String message = "Do you want to add a new level for a displayed image?";
                int clearRecords = JOptionPane.showConfirmDialog(f, message, "Add new level", JOptionPane.OK_CANCEL_OPTION);
                if (clearRecords == JOptionPane.OK_OPTION) {
                    
                    JButton button = (JButton)e.getSource();
                    JComboBox box = (JComboBox)button.getParent().getComponent(1);
                    String level = (String)box.getSelectedItem();
                    
                    List<String> labels = pm.changeDifficulty(imageName, level, null);
                    if ( labels.isEmpty() ) {                 
                        JOptionPane.showMessageDialog(f, "Selected level has been already added.");                         
                    } else {                        
                        displayLevels(labels);                        
                    }
            
                }                
            }    
            
        }
    }    
    
    
    // This method removes a selected difficulty for a displayed photo.
    class RemoveLevelHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {               
            
            if( elementsPanel.getComponentCount()<=1 ) { 
                
                JOptionPane.showMessageDialog(f, "There must be at least one level set.");
                
            } else {
                
                String imageName = photoPanel.getComponent(0).getName();
                
                String message = "Do you want to remove selected level for a displayed image?";
                int clearRecords = JOptionPane.showConfirmDialog(f, message, "Remove selected level", JOptionPane.OK_CANCEL_OPTION);
                if (clearRecords == JOptionPane.OK_OPTION) {                    
                   
                    String level = null;
                    Enumeration elements = group.getElements();
                    while (elements.hasMoreElements()) {
                        AbstractButton button = (AbstractButton)elements.nextElement();
                        if (button.isSelected()) {
                            level = button.getText();
                            break;
                        }
                    }
                    
                    List<String> labels = pm.changeDifficulty(imageName, null, level);                                           
                    displayLevels(labels);
                    
                }       
            }         
            
        }
    } 
    
    
    // This method displays best results for a selected photo and difficulty
    // or clears records for a selected photo and difficulty.
    class RecordsHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {            
             
            String imageName = photoPanel.getComponent(0).getName();
                        
            String noOfElements = null;
            Enumeration elements = group.getElements();
            while (elements.hasMoreElements()) {
                AbstractButton button = (AbstractButton)elements.nextElement();
                if (button.isSelected()) {
                    noOfElements = button.getText();
                    break;
                }
            }
            
            String recordsFileName = imageName + "_" + noOfElements + ".txt";
            
            JButton button = (JButton)e.getSource();
            if ( button.getText().equals("Show records") ) {                
                 List<Record> moveRecords = pm.getAllMoveRecords(recordsFileName);            
                 List<Record> timeRecords = pm.getAllTimeRecords(recordsFileName);
                 String imagePath = photosDirectoryPath + imageName + ".jpg";
                 
                 displayRecords(imagePath, moveRecords, timeRecords, noOfElements, null, null);            
             } else {    
                 String message = "Do you want to clear records for a displayed image cut into " + noOfElements + " number of pieces?";
                 int clearRecords = JOptionPane.showConfirmDialog(f, message, "Clear records", JOptionPane.OK_CANCEL_OPTION);
                 if (clearRecords == JOptionPane.OK_OPTION) {
                     pm.clearRecords(recordsFileName);
                 }                
             }  
            
        }
    }
    
    
    // This method clears all records for a selected photo.
    class ClearAllRecordsHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
                        
            String imageName = photoPanel.getComponent(0).getName();            
            
            String message = "Do you want to clear all records for a displayed image?";
            int clearRecords = JOptionPane.showConfirmDialog(f, message, "Clear all records", JOptionPane.OK_CANCEL_OPTION);
            if (clearRecords == JOptionPane.OK_OPTION) {            
            
                Enumeration elements = group.getElements();
                while (elements.hasMoreElements()) {
                    
                    AbstractButton button = (AbstractButton)elements.nextElement();                
                    String noOfElements = button.getText();
                
                    String recordsFileName = imageName + "_" + noOfElements + ".txt";
                    pm.clearRecords(recordsFileName);
                    
                }                              
                
            }              
            
        }
    }
     
    
    // This method opens a window with best results.
    // It is public so that it can be used by PlayPuzleGui class to display best results after each finished game.
    public static void displayRecords(String imagePath, List<Record> moveRecords, List<Record> timeRecords, String noOfElements, Record newMoveRecord, Record newTimeRecord) {
        
        centralPanel.removeAll();
        centralPanel.repaint();            
        centralPanel.add(recordsPanel);
        
        StyleContext recordsContext = new StyleContext();
        
        Style recordsStyle = recordsContext.getStyle(StyleContext.DEFAULT_STYLE);
        StyleConstants.setAlignment(recordsStyle, StyleConstants.ALIGN_CENTER);
        StyleConstants.setBold(recordsStyle, true);
        StyleConstants.setFontFamily(recordsStyle, "TimesNewRoman");
        StyleConstants.setFontSize(recordsStyle, 16);        
    
        Style recordsStyleRed = recordsContext.addStyle("RecordsStyleRed", recordsStyle);
        StyleConstants.setAlignment(recordsStyleRed, StyleConstants.ALIGN_CENTER);
        StyleConstants.setBold(recordsStyleRed, true);
        StyleConstants.setFontFamily(recordsStyleRed, "TimesNewRoman");
        StyleConstants.setFontSize(recordsStyleRed, 16);       
        StyleConstants.setForeground(recordsStyleRed, Color.RED);     
        
        DefaultStyledDocument movesDsd = new DefaultStyledDocument(recordsContext);
        DefaultStyledDocument timeDsd = new DefaultStyledDocument(recordsContext);
        
        try {
            // Prints up to 10 best results in a number of moves. 
            movesDsd.insertString(movesDsd.getLength(), "Fewest moves results:\n\n", recordsStyle);
        
            for (Record nextRecord : moveRecords) {                                                     
                String line = nextRecord.getName() + ": " + (int)nextRecord.getResult();
                if ( newMoveRecord!=null && nextRecord.getName().equals(newMoveRecord.getName()) && nextRecord.getResult()==newMoveRecord.getResult()) {
                    movesDsd.insertString(movesDsd.getLength(), line + "\n", recordsStyleRed);
                    newMoveRecord = null;
                } else {
                    movesDsd.insertString(movesDsd.getLength(), line + "\n", recordsStyle); 
                }
            }            
           
            // Prints up to 10 best time results.
            timeDsd.insertString(timeDsd.getLength(), "Shortest time results:\n\n", recordsStyle);
            
            for (Record nextRecord : timeRecords) {
                java.text.DecimalFormat df = new java.text.DecimalFormat();
                df.setMinimumFractionDigits(2);
                String line = nextRecord.getName() + ": " + df.format(nextRecord.getResult());
                if (newTimeRecord!=null && nextRecord.getName().equals(newTimeRecord.getName()) && nextRecord.getResult()==newTimeRecord.getResult()) {
                    timeDsd.insertString(timeDsd.getLength(), line + "\n", recordsStyleRed);
                    newTimeRecord = null;
                } else {
                    timeDsd.insertString(timeDsd.getLength(), line + "\n", recordsStyle); 
                }                
            }
            
        } catch (BadLocationException ble) {
            System.err.println(ble.getMessage());
        }
        
        recordsMovesTp.setDocument(movesDsd);
        recordsTimeTp.setDocument(timeDsd);        
        
        // Shows a photo for which best results are displayed.
        recordsImagePanel.removeAll();
        recordsImagePanel.repaint();
        
        JPanel photoPanel = new JPanel();
        photoPanel.setLayout(new BorderLayout());
        photoPanel.setBackground(new Color(245,245,210));
        
        PhotoRescaled photo = new PhotoRescaled(imagePath, 250, 200);
        
        // Shows a number of elements for which best results are displayed.
        JLabel label = new JLabel(noOfElements, JLabel.CENTER);
        label.setFont(new Font("TimesNewRoman", Font.BOLD, 14));
        
        photoPanel.add(photo, BorderLayout.CENTER);
        photoPanel.add(label, BorderLayout.SOUTH);

        recordsImagePanel.add(photoPanel);
                    
        f.toFront();
    }   
    
    
    // This method displays a panel containing possible difficulties.
    private void displayLevels(List<String> labels) {
        
        elementsPanel.removeAll();
        elementsPanel.repaint(); 
                    
        group = new ButtonGroup();            
        for (String label : labels) {
            JRadioButton radioButton = new JRadioButton(label);
            radioButton.setBackground(new Color(245,245,210));              
            elementsPanel.add(radioButton);
            group.add(radioButton);
        }
            
        JRadioButton selected = (JRadioButton)elementsPanel.getComponent(0);
        selected.setSelected(true);
        elementsPanel.validate();
        
    }    
    

}
